﻿/////////////////////////////////////////////////////////////////////////
//                                                                     //
//    MTGProject - A Magic The Gathering Networked Environment         //
//                                                                     //
//      Copyright (c) 2008-2009 by The MTGProject Team (CSC230)        //
//                                                                     //
// This file is part of MTGProject.                                    //
//                                                                     //
// MTGProject is free software; you can redistribute it and/or         //
// modify it under the terms of the GNU Lesser General Public          //
// License as published by the Free Software Foundation; either        //
// version 3 of the License, or (at your option) any later version.    //
//                                                                     //
// This library is distributed in the hope that it will be useful,     //
// but WITHOUT ANY WARRANTY; without even the implied warranty of      //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the       //
// GNU Lesser General Public License for more details.                 //
//                                                                     //
// You should have received a copy of the GNU Lesser General Public    //
// License along with this library; if not, write to the Free Software //
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA           //
// 02111-1307, USA, or contact the author(s):                          //
//                                                                     //
// Ruben Acuna <flyingfowlsoftware@earthlink.net>                      //
//                                                                     //
/////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace MTGProject
{
    public class CardCreature : IPermanent
    {
        #region interface variables

        //private LinkedList<ActivatedAbility> activatedAbilities;
        private LinkedList<CreatureKeyword> keywords;
        private string name;
        private string script;
        private bool isTapped;
        private bool isSick;
        private LinkedList<ManaColor> cost;
        private LinkedList<ManaColor> colors;
        private LinkedList<CreatureType> types;
        private string imageURL;
        private ICard parent;

        #endregion

        #region variables

        private int power;
        private int toughness;
        private int health;
        private int temporaryCountersOSO;
        LinkedList<CreatureKeyword> temporaryKeywords;

        private IScriptCardCreature scriptObject = null;

        #endregion

        #region properties

        #region interface properties

        public bool IsTapped
        {
            get { return isTapped; }
            set { isTapped = value; }
        }

        public LinkedList<ManaColor> Cost
        {
            get { return cost; }
            set { cost = value; }
        }

        public LinkedList<ManaColor> Colors
        {
            get { return colors; }
            set { colors = value; }
        }

        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        public string Script
        {
            get { return script; }
            set { script = value; }
        }

        public string ImageURL
        {
            get { return imageURL; }
            set { imageURL = value; }
        }

        public ICard Parent
        {
            get { return parent; }
            set { parent = value; }
        }

        #endregion

        #region properties

        public int Toughness
        {
            get { return toughness + temporaryCountersOSO; }
            set { toughness = value; }
        }

        public int Power
        {
            get { return power + temporaryCountersOSO; }
            set { power = value; }
        }

        public LinkedList<CreatureType> Types
        {
            get { return types; }
            set { types = value; }
        }

        public bool IsSick
        {
            get { return isSick; }
            set { isSick = value; }
        }

        public LinkedList<CreatureKeyword> Keywords
        {
            get { return keywords; }
            set { keywords = value; }
        }

        public int Health
        {
            get { return health; }
            set { health = value; }
        }

        public int TemporaryCountersOSO
        {
            get { return temporaryCountersOSO; }
            set { temporaryCountersOSO = value; }
        }

        public LinkedList<CreatureKeyword> TemporaryKeywords
        {
            get { return temporaryKeywords; }
            set { temporaryKeywords = value; }
        }

        public int ActivatedAbilities
        {
            get { return scriptObject.ActivatedAbilities; }
        }

        #endregion

        #endregion

        #region constructor

        public CardCreature(string name, LinkedList<ManaColor> colors, LinkedList<ManaColor> cost,
                            LinkedList<CreatureType> types, LinkedList<CreatureKeyword> keywords,
                            int power, int toughness, string script, string imageURL, ICard parent)
        {
            this.name = name;            
            this.isTapped = false;//Rule: Creatures come into play untapped.
            this.isSick = true;   //Rule: When a creature first comes into play it suffers from Summoning Sickness.
            this.colors = colors;
            this.cost = cost;
            this.power = power;
            this.toughness = toughness;
            this.health = toughness;
            this.keywords = keywords;
            this.types = types;
            this.script = script;
            this.imageURL = imageURL;
            this.health = toughness;
            this.parent = parent;
            

            temporaryCountersOSO = 0;
            temporaryKeywords = new LinkedList<CreatureKeyword>();

            //Keyword: HASTE (complete)
            if (HasKeyword(CreatureKeyword.HASTE))
                this.isSick = false;
        }

        #endregion

        #region methods

        /// <summary>
        /// Returns true if a creature has a certain keyword or if the creature's script has the keyword.
        /// </summary>
        /// <param name="keyword">Keyword to check.</param>
        /// <returns>True or false.</returns>
        public bool HasKeyword(CreatureKeyword keyword)
        {
            bool scriptHasKeyword = false;

            if (scriptObject != null) //HACK: This will be run in the constructor before we have a chance to run StartScript().
                scriptHasKeyword = scriptObject.HasKeyword(keyword); //SCRIPT HOOK

            if (keywords.Contains(keyword) || temporaryKeywords.Contains(keyword) || scriptHasKeyword)
                return true;

            return false;
        }

        /// <summary>
        /// Deal damage to creature. Damage will be transformed by script.
        /// </summary>
        /// <param name="amount">Damage.</param>
        public void TakeDamage(int amount, object cause)
        {
            int actualDamage = Math.Abs(amount);

            if (cause is ICard)
            {
                if (HasKeyword(CreatureKeyword.PROTECTION_WHITE) && ((ICard)cause).Colors.Contains(ManaColor.WHITE))
                    actualDamage = 0;
                else if (HasKeyword(CreatureKeyword.PROTECTION_BLUE) && ((ICard)cause).Colors.Contains(ManaColor.BLUE))
                    actualDamage = 0;
                else if (HasKeyword(CreatureKeyword.PROTECTION_BLACK) && ((ICard)cause).Colors.Contains(ManaColor.BLACK))
                    actualDamage = 0;
                else if (HasKeyword(CreatureKeyword.PROTECTION_RED) && ((ICard)cause).Colors.Contains(ManaColor.RED))
                    actualDamage = 0;
                else if (HasKeyword(CreatureKeyword.PROTECTION_GREEN) && ((ICard)cause).Colors.Contains(ManaColor.GREEN))
                    actualDamage = 0;
            }

            if(actualDamage != 0)
                actualDamage = scriptObject.TransformDamageTaken(amount); //SCRIPT HOOK
            
            health -= actualDamage;
        }

        /// <summary>
        /// Returns the current amount of damage this creature will do to a player or creature.
        /// </summary>
        /// <returns>Damage.</returns>
        public int DealDamage()
        {
            int combatDeal = Power; //must use property since that has counters added.

            //Keyword: DOUBLE_STRIKE (complete)
            //Rule: Creatures with Double Strike deal damage twice.
            if (HasKeyword(CreatureKeyword.DOUBLE_STRIKE))
                combatDeal *= 2;

            return combatDeal;
        }

        public void ActivateAbility(int number)
        {
            scriptObject.ActivateAbility(number);
        }

        #endregion

        #region interface methods

        //See ICard.
        public void StartScript(PlayerController controller)
        {
            if (File.Exists(Scripts.LOCATION + script))
            {
                scriptObject = (IScriptCardCreature)UtilScripts.Load(Scripts.LOCATION + Script, "CardScript");

                scriptObject.Start(this, controller);
            }
            else
                throw new IOException("Can't find script " + script);
        }

        #endregion

        #region interface scripting hooks

        //See ICard.
        public void OnResolve()
        {
            scriptObject.OnResolve(); //SCRIPT HOOK
        }

        //See ICard.

        public void OnPayCost()
        {
            scriptObject.OnPayCost(); //SCRIPT HOOK
        }

        //See IPermanent.
        public void OnTap()
        {
            scriptObject.OnTap(); //SCRIPT HOOK
        }

        //See IPermanent.
        public void OnUpkeep()
        {
            scriptObject.OnUpkeep(); //SCRIPT HOOK
        }

        //See IPermanent.
        public void Update(Observation message, object sender, object cause)
        {
            scriptObject.Update(message, sender, cause);
        }

        #endregion

        #region scripting hooks

        public void OnAttacks()
        {
            scriptObject.OnAttacks(); //SCRIPT HOOK
        }

        public void OnBlocks()
        {
            scriptObject.OnBlocks(); //SCRIPT HOOK
        }

        public void OnDeath()
        {
            scriptObject.OnDeath(); //SCRIPT HOOK
        }

        #endregion
    }
}
